package com.lingjtx.auth.handle;

import com.alibaba.fastjson2.JSON;
import com.lingjtx.auth.dao.TocUserAuthorizationMapper;
import com.lingjtx.auth.dao.TocUserInfoMapper;
import com.lingjtx.auth.dao.TocUserLoginLogMapper;
import com.lingjtx.auth.dao.UserMapper;
import com.lingjtx.auth.entity.TocUserAuthorization;
import com.lingjtx.auth.entity.TocUserInfo;
import com.lingjtx.auth.entity.TocUserLoginLog;
import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.constant.RedisConfig;
import com.lingjtx.common.core.handle.ObjectPool;
import com.lingjtx.common.core.token.AuthToken;
import com.lingjtx.common.core.token.LoginMode;
import com.lingjtx.common.core.token.UserDetail;
import com.lingjtx.common.core.token.UserVo;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.ip.IPUtils;
import com.lingjtx.common.other.model.weixin.UserInfoResponse;
import com.lingjtx.common.redis.service.IRedisService;
import com.lingjtx.common.security.model.LoginPo;
import com.lingjtx.common.thread.pooling.ObjectPoolTemplate;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.net.http.HttpClient;
import java.util.Date;

@Service
public class TocAuthService implements AuthHandle {

    private final ObjectPoolTemplate<HttpClient> httpObjectPoolTemplate;
    private final IRedisService redisService;
    private final TocUserLoginLogMapper userLoginLogMapper;
    private final TocUserInfoMapper userInfoMapper;
    private final TocUserAuthorizationMapper userAuthorizationMapper;
    private final UserMapper userMapper;

    public TocAuthService(@Qualifier("httpObjectPoolTemplate") ObjectPoolTemplate<HttpClient> httpObjectPoolTemplate,
                          IRedisService redisService,
                          TocUserLoginLogMapper userLoginLogMapper,
                          TocUserInfoMapper userInfoMapper,
                          TocUserAuthorizationMapper userAuthorizationMapper,
                          UserMapper userMapper) {
        this.httpObjectPoolTemplate = httpObjectPoolTemplate;
        this.redisService = redisService;
        this.userLoginLogMapper = userLoginLogMapper;
        this.userInfoMapper = userInfoMapper;
        this.userAuthorizationMapper = userAuthorizationMapper;
        this.userMapper = userMapper;
    }

    @Override
    public String getUserType() {
        return Const.UserType.TOC;
    }

    @Override
    public UserVo selectUserByIdentifier(String identifier) {
        return userMapper.selectUserByIdentifier(identifier, getUserType());
    }

    @Override
    public void register(LoginMode model, LoginPo loginPo, UserVo user, HttpServletRequest request) {
        if (LoginMode.REFRESH_TOKEN.equals(model)) {
            return;
        }
        if (user == null) { // 如果 user 为空，直接注册
            TocUserInfo userInfo = setUser(loginPo.getWxOpenid());
            if (LoginMode.WX_OPENID.equals(model)) { // 微信授权登录
                userInfo.setWxOpenid(loginPo.getIdentifier());
                createUser(userInfo, loginPo.getIdentifier(), Const.IdentityType.WEXIN);
            }
            if (LoginMode.MOBILE.equals(model)) { // 手机号码登录
                if (StringUtil.isNotEmpty(loginPo.getFaceid())) { // 人脸注册
                    userInfo.setFaceid(loginPo.getIdentifier());
                    createUser(userInfo, loginPo.getIdentifier(), Const.IdentityType.FACE);
                } else {
                    userInfo.setMobile(loginPo.getIdentifier());
                    createUser(userInfo, loginPo.getIdentifier(), Const.IdentityType.MOBILE);
                    if (StringUtil.isNotEmpty(loginPo.getWxOpenid())) { // 微信注册
                        createUserAuthorization(loginPo.getWxOpenid(), userInfo.getUserId(), Const.IdentityType.WEXIN, null);
                    }
                }
            }
            if (LoginMode.EMAIL.equals(model)) { // 邮箱登录
                userInfo.setEmail(loginPo.getIdentifier());
                createUser(userInfo, loginPo.getIdentifier(), Const.IdentityType.EMAIL);
            }
        } else { // 已注册存在的账号
            if (StringUtil.isNotEmpty(loginPo.getWxOpenid())) { // 把第三方openid 绑定在此用户上面
                TocUserInfo userInfo = setUser(loginPo.getWxOpenid());
                userInfo.setUserId(user.getUserId());
                userInfo.setWxOpenid(loginPo.getWxOpenid());
                userInfoMapper.updateById(userInfo);
                createUserAuthorization(loginPo.getWxOpenid(), user.getUserId(), Const.IdentityType.WEXIN, user);
            }
            if (StringUtil.isNotEmpty(loginPo.getFaceid())) { // 把人脸faceid 绑定在此用户上面
                TocUserInfo userInfo = setUser(null);
                userInfo.setUserId(user.getUserId());
                userInfo.setFaceid(loginPo.getFaceid());
                userInfoMapper.updateById(userInfo);
                createUserAuthorization(loginPo.getFaceid(), user.getUserId(), Const.IdentityType.FACE, user);
            }
            // 插入一条登录日志
            insertLoginLog(request, user.getUserId(), loginPo);
        }
    }

    @Override
    public ObjectPool<HttpClient> getObjectPool() {
        return httpObjectPoolTemplate;
    }

    @Override
    public void insertLoginLog(HttpServletRequest request, Long userId, LoginPo loginPo) {
        String ip = request.getHeader("x-real-ip");
        if (userId == null) { // 退出登录
            String token = request.getHeader(Const.AuthTokenMap.AUTHORIZATION);
            UserDetail user = AuthToken.getUser(token);
            if (user != null) {
                TocUserLoginLog loginLog = userLoginLogMapper.selectLastLoginLog(user.getUserId());
                if (loginLog != null) {
                    loginLog.setLoginStatus(Const.LoginStatus.LOGOUT);
                    insertDatabase(ip, loginLog);
                }
            }
        } else { // 登录
            TocUserLoginLog loginLog = new TocUserLoginLog();
            loginLog.setUserId(userId);
            loginLog.setLoginStatus(Const.LoginStatus.LOGIN);
            loginLog.setDeviceModel(loginPo.getDeviceModel());
            loginLog.setDeviceUid(loginPo.getDeviceUid());
            loginLog.setOperationDevice(loginPo.getOperationDevice());
            loginLog.setCreateTime(new Date());
            redisService.set(RedisConfig.KEY_LOGIN_LOG + userId,
                    JSON.toJSONString(loginLog),
                    RedisConfig.TIMEOUT_REFRESH_TOKEN);
            insertDatabase(ip, loginLog);
        }
    }

    private TocUserInfo setUser(String wxOpenid) {
        TocUserInfo userInfo = new TocUserInfo();
        userInfo.setNickname("用户" + StringUtil.randomCode(4));
        userInfo.setAvatar(Const.DEFAULT_AVATAR);
        UserInfoResponse userInfoResponse = (UserInfoResponse) redisService.get(wxOpenid);
        if (userInfoResponse != null) {
            userInfo.setWxOpenid(userInfoResponse.getOpenid());
            userInfo.setAvatar(userInfoResponse.getHeadimgurl());
            userInfo.setNickname(userInfoResponse.getNickname());
            userInfo.setSex((byte) (userInfoResponse.getSex() + 1));
        }
        return userInfo;
    }

    private void createUserAuthorization(String identifier, Long userId, byte identityType, UserVo user) {
        UserVo wxUser = userMapper.selectUserByIdentifier(identifier, getUserType());
        if (wxUser == null) { // 新增微信授权
            TocUserAuthorization auth = new TocUserAuthorization();
            auth.setUserId(userId);
            auth.setIdentityType(identityType);
            auth.setIdentifier(identifier);
            userAuthorizationMapper.insert(auth);
        } else { // 修改微信授权
            if (user != null) {
                TocUserAuthorization auth = new TocUserAuthorization();
                auth.setUserId(user.getUserId());
                auth.setIdentifier(identifier);
                userAuthorizationMapper.updateById(auth);
            }
        }
    }

    private void createUser(TocUserInfo userInfo, String identifier, byte identityType) {
        userInfoMapper.insert(userInfo);
        TocUserAuthorization authorization = new TocUserAuthorization();
        authorization.setUserId(userInfo.getUserId());
        authorization.setIdentityType(identityType);
        authorization.setIdentifier(identifier);
        userAuthorizationMapper.insert(authorization);
    }

    private void insertDatabase(String ip, TocUserLoginLog loginLog) {
        loginLog.setIp(ip);
        if (StringUtil.isNotEmpty(ip)) {
            loginLog.setAddress(IPUtils.getArea(ip).getName());
        }
        userLoginLogMapper.insert(loginLog);
    }
}
